package ae.pcfc.cldos.online.common.clddb.domain.manager.provider;

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Value;

import ae.pcfc.cldos.online.common.ConstantsCommon;
import ae.pcfc.cldos.online.common.ConstantsCommon.Steps;
import ae.pcfc.cldos.online.common.clddb.dao.AppMetaDataDAO;
import ae.pcfc.cldos.online.common.clddb.dao.ApplicationStatusDAO;
import ae.pcfc.cldos.online.common.clddb.dao.ServiceMasterDAO;
import ae.pcfc.cldos.online.common.clddb.domain.AppMetaData;
import ae.pcfc.cldos.online.common.clddb.domain.ApplicationStatus;
import ae.pcfc.cldos.online.common.clddb.domain.ServiceMaster;
import ae.pcfc.cldos.online.common.clddb.domain.manager.AppMetaDataDOM;
import ae.pcfc.cldos.online.common.etksdb.dao.EtksAppMetaDataDAO;
import ae.pcfc.cldos.online.common.etksdb.domain.EtksAppMetaData;
import ae.pcfc.cldos.online.common.exception.BadAppException;
import ae.pcfc.cldos.online.common.manager.EncryptionManager;
import ae.pcfc.cldos.online.common.vo.UserInformationVO;
import ae.pcfc.cldos.online.common.vo.tasks.TaskRequestDbRestrictions;

/**
 * 
 * @author ammar
 *
 */
public class AppMetaDataDOMImpl implements AppMetaDataDOM {

	@Value("${application.url}")
	private String appUrl;
	
	@Value("${application.task.url}")
	private String taskUrl;
	
	private AppMetaDataDAO appMetaDataDAO;
	
	private EtksAppMetaDataDAO etksAppMetaDataDAO;
	
	private ServiceMasterDAO serviceMasterDAO;
	
	private ApplicationStatusDAO applicationStatusDAO;
	
	private EncryptionManager encryptionManager;
	
	public static final Map<Steps, Set<Long>> STEPS_STATUSES_MAPPING = new HashMap<Steps, Set<Long>>(){
		/**
		 * 
		 */
		private static final long serialVersionUID = -6907394802282944027L;

		{
			put(ConstantsCommon.Steps.RESUBMIT, new HashSet<Long>(Arrays.asList(
					new Long[]{	ApplicationStatus.STATUS_REJECTED_BY_ONLINE_ADMIN, ApplicationStatus.STATUS_REJECTED_BY_GENERAL_ADMIN }
			)));
			
			put(ConstantsCommon.Steps.MAIN_ADMIN_APPROVE, new HashSet<Long>(Arrays.asList(
					new Long[]{	ApplicationStatus.STATUS_INITIATED, ApplicationStatus.STATUS_RESUBMITED }
			)));
			put(ConstantsCommon.Steps.DOCUMENT_AND_DATA_VALIDATION, new HashSet<Long>(Arrays.asList(
					new Long[]{	ApplicationStatus.STATUS_APPROVED_BY_ONLINE_ADMIN }
			)));
			
			put(ConstantsCommon.Steps.EXIT_PAPER_SUBMIT, new HashSet<Long>(Arrays.asList(
					new Long[]{	ApplicationStatus.STATUS_EXIT_PAPER_SUBMIT }
			)));
		}
	};
	
	public void setEncryptionManager(EncryptionManager encryptionManager) {
		this.encryptionManager = encryptionManager;
	}
	
	public void setApplicationStatusDAO(
			ApplicationStatusDAO applicationStatusDAO) {
		this.applicationStatusDAO = applicationStatusDAO;
	}
	
	public void setServiceMasterDAO(ServiceMasterDAO serviceMasterDAO) {
		this.serviceMasterDAO = serviceMasterDAO;
	}
	
	public void setEtksAppMetaDataDAO(EtksAppMetaDataDAO etksAppMetaDataDAO) {
		this.etksAppMetaDataDAO = etksAppMetaDataDAO;
	}
	
	public void setAppMetaDataDAO(AppMetaDataDAO appMetaDataDAO) {
		this.appMetaDataDAO = appMetaDataDAO;
	}
	
	public void add(AppMetaData appMetaData){
		appMetaDataDAO.add(appMetaData);
	}
	
	public void updateAndAddEtks(AppMetaData appMetaData){
		appMetaDataDAO.update(appMetaData);
		addEtksAppMetaData(appMetaData);
	}
	
	public void addEtksAppMetaData(AppMetaData appMetaData){
		String onlineAppId = appMetaData.getApplicationId().toString();
		ServiceMaster serviceMaster = serviceMasterDAO.findById(appMetaData.getServiceCode());
		ApplicationStatus applicationStatus = applicationStatusDAO.findById(appMetaData.getStatusCode());
		
		EtksAppMetaData etksAppMetaData = new EtksAppMetaData();
		etksAppMetaData.setApplicationDate(appMetaData.getApplicationDate().toString());
		if(applicationStatus.getStatusType().equals(ApplicationStatus.__STATUS_ONLINE)){
			etksAppMetaData.setApplicationLink(appUrl+taskUrl+encryptionManager.encryptAndEncode(onlineAppId));
		} else {
			etksAppMetaData.setApplicationLink(null);
		}
		etksAppMetaData.setClientId(appMetaData.getClientId());
		etksAppMetaData.setClientRefNo(EtksAppMetaData.ONLINE_APP_ID_PREFIX+appMetaData.getClientRefNo());
		etksAppMetaData.setProcessCode(serviceMaster.getEtksCode());
		etksAppMetaData.setUserId(appMetaData.getUserId());
		if(appMetaData.getWfIncidentId() != null){
			etksAppMetaData.setWfIncidentId(appMetaData.getWfIncidentId());
			etksAppMetaData.setWfInitiatedBy(appMetaData.getWfInitiatedBy());
			etksAppMetaData.setWfStatus(appMetaData.getWfStatus());
		}else{
			etksAppMetaData.setWfIncidentId(" ");
			etksAppMetaData.setWfInitiatedBy(" ");
			etksAppMetaData.setWfStatus(" ");
		}
		etksAppMetaData.setWfStatusEn(applicationStatus.getStatusDesc());
		etksAppMetaData.setWfStatusAr(applicationStatus.getStatusDesc());
		
		etksAppMetaDataDAO.add(etksAppMetaData);
	}
	
	public void update(AppMetaData appMetaData){
		appMetaDataDAO.update(appMetaData);
		
		EtksAppMetaData etksAppMetaData = etksAppMetaDataDAO.getByCldosAppId(appMetaData.getClientRefNo());
		if(etksAppMetaData!=null){
			ApplicationStatus applicationStatus = applicationStatusDAO.findById(appMetaData.getStatusCode());
			etksAppMetaData.setWfStatusAr(applicationStatus.getStatusDesc());
			etksAppMetaData.setWfStatusEn(applicationStatus.getStatusDesc());
			if(appMetaData.getWfIncidentId() != null){
				etksAppMetaData.setWfIncidentId(appMetaData.getWfIncidentId());
				etksAppMetaData.setWfInitiatedBy(appMetaData.getWfInitiatedBy());
			}
			if(applicationStatus.getStatusType().equals(ApplicationStatus.__STATUS_ONLINE)){
				etksAppMetaData.setApplicationLink(appUrl+taskUrl+encryptionManager
						.encryptAndEncode(appMetaData.getApplicationId().toString()));
			} else {
				etksAppMetaData.setApplicationLink(null);
			}
			etksAppMetaDataDAO.update(etksAppMetaData);
		}
	}
	
	public AppMetaData getAppMetaDataById(String applicationId){
		AppMetaData appMetaData =  appMetaDataDAO.getPlainAppMetaDataById(Long.parseLong(applicationId));
		
		return appMetaDataDAO.getAppMetaDataById(appMetaData.getApplicationId(), appMetaData.getProcessCode());
	}
	
	public AppMetaData getPlainAppMetaDataById(String applicationId) throws BadAppException{
		Long appId = null;
		try{
			appId = Long.parseLong(applicationId);
		} catch (Exception e) {
			throw new BadAppException("Bad App");
		}
		return appMetaDataDAO.getPlainAppMetaDataById(appId);
	}
	public List<AppMetaData> getAllAppRequests(UserInformationVO userInformationVO, TaskRequestDbRestrictions taskRequestDbRestrictions){
		return appMetaDataDAO.getAllAppRequests(userInformationVO, taskRequestDbRestrictions);
	}
	public Integer getApplicationCount(UserInformationVO userInformationVO, TaskRequestDbRestrictions taskRequestDbRestrictions){
		return appMetaDataDAO.getApplicationCount(userInformationVO, taskRequestDbRestrictions);
	}
	
	private AppMetaData getAppMetaDataById(String appId, String processCode, Steps step, Long clientId, boolean isGeneralAdmin) throws BadAppException{
		Long applicationId = null;
		try{
			applicationId = Long.parseLong(appId);
		}catch (Exception e) {
			throw new BadAppException("Bad App");
		}
		if(applicationId==null){
			throw new BadAppException("Bad App");
		}
		
		AppMetaData appMetaData = appMetaDataDAO.getAppMetaDataById(applicationId, processCode); 
		if(appMetaData==null || !appMetaData.getProcessCode().equalsIgnoreCase(processCode) ||
				(!isGeneralAdmin && !appMetaData.getClientId().equals(clientId))){
			throw new BadAppException("Bad App");
		}
		if(!step.equals(Steps.ALL_APP_REQUEST) && !STEPS_STATUSES_MAPPING.get(step).contains(appMetaData.getStatusCode())){
			throw new BadAppException("Bad App");
		}
		return appMetaData;
	}
	
	public AppMetaData getAppMetaDataById(String appId, String processCode, Steps step, Long clientId) throws BadAppException{
		return getAppMetaDataById(appId, processCode, step, clientId, false);
	}
	
	public AppMetaData getAppMetaDataByIdForGeneralAdmin(String appId, String processCode, Steps step) throws BadAppException{
		return getAppMetaDataById(appId, processCode, step, null, true);
	}
	/**
	 * @param userInformationVO
	 * @param taskRequestDbRestrictions
	 * @return
	 */
	public List<AppMetaData> getAllApplications(UserInformationVO userInformationVO, TaskRequestDbRestrictions taskRequestDbRestrictions){
		return appMetaDataDAO.getAllApplications(userInformationVO, taskRequestDbRestrictions);
	}
	
	public boolean isEmployeeHasRequest(String passportName, String passportNo){
		boolean result = false;
		List<AppMetaData> tasksForEmployees = 
				appMetaDataDAO.getAppMetaDataByPassportDetails(passportName, passportNo);
		if(tasksForEmployees!=null){
			for(AppMetaData appMetaData : tasksForEmployees){
				Long statusCode = appMetaData.getStatusCode();
				if(ApplicationStatus.PENDING_STATUSES.contains(statusCode)){
					result = true;
					break;
				}
			}
		}
		return result;
	}
	
	public Integer getEmploymentVisaPendingRequests(Long clientId){
		return appMetaDataDAO.getEmploymentVisaPendingRequests(clientId);
	}
	/**
	 * @param clientId
	 * @return
	 */
	public Integer getVisitVisaPendingRequests(Long clientId){
		return appMetaDataDAO.getVisitVisaPendingRequests(clientId);
	}
	
	public AppMetaData getApplicationByReferenceNumber(String clientRefNo){
		return appMetaDataDAO.getApplicationByReferenceNumber(clientRefNo);
	}
	
	public boolean isEmployeeHasRequest(String empId){
		return appMetaDataDAO.getRequestAmountByPersonId(empId).compareTo(0)>0;
	}
	
	/**
	 * @param clientId
	 * @return
	 */
	public Integer getPendingRequests(Long clientId){
		return appMetaDataDAO.getVisitVisaPendingRequests(clientId);
	}
	
	public AppMetaData findAppMetaDataById(Long appId){
		return appMetaDataDAO.findAppMetaDataById(appId);
	}
	
	
}
